#include <glib.h>
#include <gio/gio.h>
#include <stdio.h>
#include <termios.h>
#include <unistd.h>

#define MAX_LINES 10
#define MAX_LINE_LENGTH 80

static gchar *lines[MAX_LINES];
static gint current_line = 0;
static gint num_lines = 0;
static GIOChannel *channel;

static void print_lines() {
    gint i;
    for (i = 0; i < num_lines; i++) {
        printf("%s\n", lines[i]);
    }
}

static void add_line(const gchar *line) {
    if (num_lines < MAX_LINES) {
        lines[num_lines] = g_strdup(line);
        num_lines++;
    } else {
        g_free(lines[0]);
        memmove(lines, lines + 1, sizeof(gchar *) * (MAX_LINES - 1));
        lines[MAX_LINES - 1] = g_strdup(line);
    }
}

static gboolean read_cb(GIOChannel *source, GIOCondition condition, gpointer data) {
    gchar *line = NULL;
    gsize length = 0;
    GError *error = NULL;

    if (g_io_channel_read_line(source, &line, &length, NULL, &error) == G_IO_ERROR_NONE) {
        add_line(line);
        print_lines();
        g_free(line);
    } else {
        g_printerr("Error reading from server: %s\n", error->message);
        g_error_free(error);
        return FALSE;
    }

    return TRUE;
}

static void set_terminal_mode() {
    struct termios t;
    tcgetattr(STDIN_FILENO, &t);
    t.c_lflag &= ~(ICANON | ECHO);
    tcsetattr(STDIN_FILENO, TCSANOW, &t);
}

static void reset_terminal_mode() {
    struct termios t;
    tcgetattr(STDIN_FILENO, &t);
    t.c_lflag |= ICANON | ECHO;
    tcsetattr(STDIN_FILENO, TCSANOW, &t);
}

static void send_message(const gchar *message) {
    GError *error = NULL;
    gsize length = strlen(message);

    if (g_io_channel_write_chars(channel, message, length, NULL, &error) == G_IO_ERROR_NONE) {
        add_line(message);
        print_lines();
    } else {
        g_printerr("Error sending message: %s\n", error->message);
        g_error_free(error);
    }
}

static gboolean stdin_cb(GIOChannel *source, GIOCondition condition, gpointer data) {
    gchar *line = NULL;
    gsize length = 0;
    GError *error = NULL;

    if (g_io_channel_read_line(source, &line, &length, NULL, &error) == G_IO_ERROR_NONE) {
        send_message(line);
        g_free(line);
    } else {
      if (error) {
        g_print("Error reading from stdin: %s\n", error->message);
        g_printerr("Error reading from stdin: %s\n", error->message);
        g_error_free(error);
      }
        return FALSE;
    }

    return TRUE;
}
int main(int argc, char **argv) {
    GSocketClient *client;
    GSocketConnection *connection;
    GMainLoop *loop;
    GError *error = NULL;

    set_terminal_mode();

    client = g_socket_client_new();
    connection = g_socket_client_connect_to_host(client, "localhost", 1234, NULL, &error);
    if (error != NULL) {
        g_printerr("Error connecting to server: %s\n", error->message);
        g_error_free(error);
        return 1;
    }

    //channel = g_io_channel_unix_new(g_socket_connection_get_fd(connection));
    channel = g_io_channel_unix_new(g_socket_get_fd(g_socket_connection_get_socket(connection)));
    g_io_add_watch(channel, G_IO_IN, read_cb, NULL);

    GIOChannel *stdin_channel = g_io_channel_unix_new(STDIN_FILENO);
    g_io_add_watch(stdin_channel, G_IO_IN, stdin_cb, NULL);
    g_io_channel_set_flags(stdin_channel, G_IO_FLAG_NONBLOCK, NULL);

    loop = g_main_loop_new(NULL, FALSE);
    g_main_loop_run(loop);

    g_io_channel_unref(channel);
    g_io_channel_unref(stdin_channel);
    g_socket_close(client, NULL);
    g_object_unref(connection);
    g_object_unref(client);

    reset_terminal_mode();

    return 0;
}

